package com.kerwin.permmgt.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kerwin.annotations.RedisGetAndSet;
import com.kerwin.async.AsyncFactory;
import com.kerwin.async.AsyncManager;
import com.kerwin.menumgt.entity.Menu;
import com.kerwin.menumgt.mapper.MenuMapper;
import com.kerwin.permmgt.PermService;
import com.kerwin.permmgt.entity.AddPerm;
import com.kerwin.permmgt.entity.Permissions;
import com.kerwin.permmgt.entity.TreePermDetail;
import com.kerwin.permmgt.mapper.PermMapper;
import com.kerwin.utils.CRMConstant;
import com.kerwin.utils.JackSonUtil;
import com.kerwin.utils.SpringContextUtil;
import com.sun.deploy.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class PermServiceImpl extends ServiceImpl<PermMapper, Permissions> implements PermService {

    @Resource
    MenuMapper menuMapper;


    private static Logger log = LoggerFactory.getLogger(PermServiceImpl.class);
    private ObjectMapper objectMapper = JackSonUtil.objectMapper;

    /*(1)*/
  /* private static MenuMapper menuMapper;
    static{
         menuMapper = SpringContextUtil.getBean(MenuMapper.class);
    }*/
    /*(2)*/

    /*加载顺序问题*/
   /*public   MenuMapper menuMapper = SpringContextUtil.getBean(MenuMapper.class);*/


    /*获得权限菜单列表 key value Map*/
    public HashMap<String, List<String>> getAllPermName(){
        /*从容器里面拿东西*/
        MenuMapper menuMapper = SpringContextUtil.getBean(MenuMapper.class);

        /*lambda构建器*/
        LambdaQueryWrapper<Permissions> lq = new LambdaQueryWrapper<>();
        /*lambda表达式，不用写数据库名 防止打错*/
        lq.select(Permissions::getPermName);
        /*查询权限名称*/
        List<Permissions> permissions = baseMapper.selectList(lq);
        /*因为返回的是个对象，所以要把对象里面的权限名称提出来*/
        ArrayList<String> permName = new ArrayList<String>();
        /*把权限名称保存到list字符串集合*/
        permissions.forEach((a)->permName.add(a.getPermName()));
        /*权限名称,可执行操作 用的Map*/
        HashMap<String, List<String>> perm = new HashMap<>();
        /*权限名称,可执行操作 放到Map里*/

        permName.forEach(i->perm.put(i, menuMapper.getPermDetails(i)));

        return perm;

    }

    @Resource
    private RedisTemplate<String,Object> redis;
    /*把权限列表放到redis里*/
    public Map<String, List<String>> getPermDetails(){
        HashOperations<String, String,List<String>> redisForMap = redis.opsForHash();
        Map<String, List<String>> permMenu = redisForMap.entries("permMenu");
        return permMenu;
    }




    /*添加权限*/
    public void addPerm(AddPerm addPerm){
        /*添加一个对象用于mp插入数据库用*/
        Permissions permissions = new Permissions();
        /*设置名字*/
        permissions.setPermName(addPerm.getPermName());
        /*用工具类去掉 集合的[] */
        String permPerformed= StringUtils.join(addPerm.getPermPerformed(), ",");
        /*设置权限字符串*/
        permissions.setPermPerformed(permPerformed);


        /*这个地方会不会有线程问题*/
        /*给存到redis 用的map*/
        /*2进来给改了*/
        LinkedHashMap<String, String> addPermMap = new LinkedHashMap<>();
        /*1存了2的东西？*/
        addPermMap.put(addPerm.getPermName(), permPerformed);

        log.info("添加【权限菜单】到redis里");
        /*存到redis里面*/
        addPermToRedis(addPermMap);
        /*mp插入*/
        /*这里插入数据库*/

        /*异步存到数据库里面*/
        //int insert = baseMapper.insert(permissions);
        AsyncManager.execute(AsyncFactory.addPermToMySql(permissions));
    }

    @Resource
    RedisTemplate<String, Object> redisTemplate;
    /*这里插入redis*/
    /**为了高并发，不直接访问数据库，先存到redis*/
    /*用map来存*/
    public void addPermToRedis(LinkedHashMap<String, String> addPermMap) {



        HashOperations<String, String, String> hashOpera = redisTemplate.opsForHash();

        addPermMap.keySet().forEach(i->
                hashOpera.put("addPerm", i, addPermMap.get(i))
        );

    }

    /*从数据库里面拿权限数据放到redis里*/
    /*从redis里面那数据放到前端*/

    /*先把数据放到前端*/
    public List<Permissions> queryPermDetail(){
        LambdaQueryWrapper<Permissions> permWrapper = new LambdaQueryWrapper<>();
        List<Permissions> permDetail = baseMapper.selectList(permWrapper);
        /*在这里根据可执行操作id，把父子菜单查出来*/
        /*先全都查出来*/


        return permDetail;
    }

    public ArrayList<TreePermDetail> treePerm(){
        /*要删除的测试语句*/
        MenuMapper menuMapper = SpringContextUtil.getBean(MenuMapper.class);

        /*在这里先查redis*/
        /*不能用redis list数据类型*/
        /*list每取一次是弹出去一个元素，下一次又要从数据库里面查了*/
        /*因为就一个数据 给一个map 指定过期时间*/

        HashOperations<String, String, Object> hashOpera = redis.opsForHash();
        /*通过key mapKey 取数据*/
        Object permList = hashOpera.get(CRMConstant.PERM_REDIS_LIST, CRMConstant.PERM_REDIS_LIST_MAP_KEY);
        /*从redis里面取数据*/
        /*记住我用redisKey 和 mapKey 取出来的已经是List了*/
        if(permList instanceof List){
            ArrayList<TreePermDetail> treePermDetails = (ArrayList<TreePermDetail>)permList;
            log.info("从redis里面取到了 权限详情数据");
            return treePermDetails;
        }


        /*先查询所有权限的名字和可执行操作字符串*/
        List<Permissions> allPerm = queryPermDetail();

        /*这是最终输出的json集合*/
        ArrayList<TreePermDetail> treePerm = new ArrayList<>();

        /*遍历查询出来的集合*/
        for (Permissions perm : allPerm) {
            /*建立最终集合需要的对象*/
            TreePermDetail treePermObject = new TreePermDetail();
            treePermObject.setPermName(perm.getPermName());
            /*根据可执行操作字符串 查询 Menu列表*/
            List<String> Perform = Arrays.asList(perm.getPermPerformed().split(","));

            /*根据  Permissions.permPerformed 值去查菜单表*/
            LambdaQueryWrapper<Menu> menuWrapper = new LambdaQueryWrapper<>();
            menuWrapper.in(Menu::getId,Perform);
            List<Menu> allMenus = menuMapper.selectList(menuWrapper);

            /*让菜单表有层级*/
            /*父集合*/
            ArrayList<Menu> fatherMenu = new ArrayList<>();
            /*子集合*/
            ArrayList<Menu> sonMenu = new ArrayList<>();

            /*把查询出来的列表里面的元素，按pid分类*/
            allMenus.forEach(i->
            {
                if("0".equals(i.getMenuPid()))
                    fatherMenu.add(i);
                else
                    sonMenu.add(i);
            });

            /*按照pid 把子集合放入父集合*/
            fatherMenu.forEach(i->{
                sonMenu.forEach(j->{
                    if(j.getMenuPid().equals(i.getId())){
                        /*这里我需要往父菜单 List  subMenu 里面放 Menu对象*/
                        /*要先获得List集合*/
                        /*再往里面放数据*/
                        i.getSubMenu().add(j);
                    }
                });
            });

            /*这里要把层次菜单放进 对象*/
            treePermObject.getSubPerm().addAll(fatherMenu);
            /*把对象放入 最终输出的json集合*/
            treePerm.add(treePermObject);
        }

       /*String TreePerm = null;
        try {
            TreePerm = JackSonUtil.objectMapper.writeValueAsString(treePerm);
        } catch (JsonProcessingException e) {
            throw new HandlerException(E.JSON_Error);
        }*/

        /*在数据库里面查数据  存的是json  是个list*/
        hashOpera.put(CRMConstant.PERM_REDIS_LIST, CRMConstant.PERM_REDIS_LIST_MAP_KEY, treePerm);
        /*设置map集合的过期时间*/
        redisTemplate.expire(CRMConstant.PERM_REDIS_LIST, 10, TimeUnit.SECONDS);
        log.info("没有取到权限菜单，已经把数据放入redis里，并设置了10秒的过期时间");
        return treePerm;
    }


    @RedisGetAndSet(keyName=CRMConstant.PERM_NAME,clz=Permissions.class,frontLog = "从redis取出权限名称并返回",behind = "权限名称存入redis")
    public List<Permissions> getPermName(){

        /*获得redis里面的参数 需要替换的变量*/
    /*仅限于string list*/

   /* ValueOperations<String, Object> stringOpera = redisTemplate.opsForValue();
    Object o = stringOpera.get(CRMConstant.PERM_NAME); *//*1、  get参数*//*
    if(Objects.nonNull(o) && o instanceof String){
        String s = String.valueOf(o);
        try {
            log.info("从redis取出权限名称并返回");*//*日志文字*//*
            return objectMapper.readValue(s, objectMapper.getTypeFactory().constructParametricType(List.class, Permissions.class));*//*2、类的参数*//*

        } catch (JsonProcessingException e) {
            throw new HandlerException(E.JSON_ERROR);
        }

    }*/


    LambdaQueryWrapper<Permissions> permWrapper = new LambdaQueryWrapper<>();
    permWrapper.select(Permissions::getId,Permissions::getPermName);
    List<Permissions> permName = baseMapper.selectList(permWrapper);


   /* ObjectMapper objectMapper = JackSonUtil.objectMapper;
    String permNameJson=null;
    try {
        permNameJson = objectMapper.writeValueAsString(permName);
    } catch (JsonProcessingException e) {
        throw new HandlerException(E.JSON_ERROR);
    }

    stringOpera.set(CRMConstant.PERM_NAME, permNameJson, 30, TimeUnit.MINUTES);
    log.info("权限名称存入redis");*//*3、返回字符*//*


    *//*返回这个部门list*/
    return permName;

}




    }

